גם נתונים רגישים אפשר לשמור במסד נתונים. יתרה מכך, MySQL מכילה פונקציות הצפנה מובנות שיאפשרו לך להצפין ולהגן על המידע השמור באמצעות פקודה אחת קצרה.
מדי פעם יש צורך לשמור נתונים מוצפנים במסד כמו מספרי תעודות הזהות.
הצפנות כגון md5, sha1, sha256 לא מתאימות עקב היותן חד-כיווניות ללא דרך שיחזור למצב המקורי. במקומן ניתן להשתמש באחת מעשרות פונקציות ההצפנה שמציעה PHP, אבל להרוויח הרבה יותר ניתן באמצעות פונקציות ההצפנה שמציעה MySQL.
כמובן שכל הפונקציות של MySQL עובדות הרבה יותר מהר מאלה של PHP, מכיוון שהן מבוצעות בשפת C ישירה ובנוסף יתאפשר חיפוש של נתונים מוצפנים בתוך המסד.
DES_ENCRYPT
des_encrypt היא פונקציה פשוטה, המבצעת הצפנה לפי אלרגוריתם ה-des שפותח על ידי IBM לפני הרבה מאוד שנים. השימוש בה פשוט מאוד:
DES_ENCRYPT('some_secret_data','very_secret_key52@#$@#$@#$');
הפרמטר הראשון הוא הטקסט שיש להצפין, הפרמטר השני הוא מפתח סודי (סיסמה) שמשמש להצפנה; בכדי לפענח את הטקסט המוצפן יהיה צורך בדיוק באותה סיסמה.
שימוש בפועל
לצורך ההסבר ניצור טבלה עם שתי שדות, id עם מספור אוטומטי ו-encrypted מסוג blob.
CREATE TABLE IF NOT EXISTS `destest` (
`id` smallint(6) NOT NULL AUTO_INCREMENT,
`encrypted` blob NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`id` smallint(6) NOT NULL AUTO_INCREMENT,
`encrypted` blob NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
שימו לב לכך שהשדה שישמור את הנתונים המוצפנים יהיה מסוג blob (ראשי תיבות של binary large object).
תוצאת פעולת ההצפנה לרוב לא תהיה טקסט רגיל, אלה משהו בינארי לא ברור.
נכניס שורה אחת כלשהי לטבלה עם הפקודה הנ"ל:
INSERT INTO `destest` (`id`, `encrypted`) VALUES(1, DES_ENCRYPT('phpguide.co.il', 'password') )
כעת יש שורה אחת שבה מוצפן הערך phpguide.co.il עם הסיסמה password.
des_decrypt
כדי לשלוף את הערך מהטבלה נשתמש בפונקציה ההפוכה - des_decrypt, שפועלת בדיוק באותה צורה, רק שבמקום המחרוזת שיש להצפין, היא מקבלת את המידע שיש לפענח.
SELECT `id`,
DES_DECRYPT(`encrypted`, 'password')
as 'decrypted' FROM `destest`
DES_DECRYPT(`encrypted`, 'password')
as 'decrypted' FROM `destest`
שימוש עם PHP
mysql_connect(..);
mysql_select_db(..);
mysql_query("SET NAMES 'UTF-8'");
define("deskey", "uduATHd-thontseuh;wmxjk){(}{)@#(Y~~~~~:QJK)oeullr");
mysql_query("INSERT INTO `destest` (`encrypted`) VALUES
(DES_ENCRYPT('this is cool', '".deskey."'))");
$result = mysql_query("SELECT `id`,
DES_DECRYPT(`encrypted`, '".deskey."') as 'decrypted'
FROM `destest` ");
while($row = mysql_fetch_assoc($result))
{
echo $row['id'], ' -> ', $row['decrypted'], '<br/>';
}
mysql_select_db(..);
mysql_query("SET NAMES 'UTF-8'");
define("deskey", "uduATHd-thontseuh;wmxjk){(}{)@#(Y~~~~~:QJK)oeullr");
mysql_query("INSERT INTO `destest` (`encrypted`) VALUES
(DES_ENCRYPT('this is cool', '".deskey."'))");
$result = mysql_query("SELECT `id`,
DES_DECRYPT(`encrypted`, '".deskey."') as 'decrypted'
FROM `destest` ");
while($row = mysql_fetch_assoc($result))
{
echo $row['id'], ' -> ', $row['decrypted'], '<br/>';
}
שורות שבהן מוצפן טקסט עם סיסמה אחרת לא יפוענחו נכון.
איזו סיסמת הצפנה לבחור?
כמה שיותר ארוכה. מה אכפת לכם, זה לא שאתם צריכים לזכור אותה. אבל לא להגזים, 50 תווים זה מספיק. :)
שימו לב
אם פתאום תהיה לכם שגיאה בשאילתה, יש סיכוי שהודעת השגיאה תכלול חלק מהסיסמה שלכם. מאוד חשוב - אף פעם אל תציגו שגיאות למשתמש. תוכלו לקרוא איך עושים זאת כאן ואח"כ כאן.
בונוס
להצפנה בטוחה יותר ניתן אפילו להצפין כל שורה בעזרת מפתח משלה.
פשוט נוסיף למפתח ההצפנה גם את ה-id של השורה באופן הבא:
UPDATE `destest` SET
`encrypted` = DES_ENCRYPT('this is cool', CONCAT(`id`, 'mypassword') )
--
SELECT `id`,
DES_DECRYPT(`encrypted`, CONCAT(`id`, 'mypassword')) as 'decrypted'
FROM `destest`
`encrypted` = DES_ENCRYPT('this is cool', CONCAT(`id`, 'mypassword') )
--
SELECT `id`,
DES_DECRYPT(`encrypted`, CONCAT(`id`, 'mypassword')) as 'decrypted'
FROM `destest`
הפונקציה concat מחברת מחרוזות כמו אופרטור הנקודה ב-PHP. השורה הראשונה תוצפן עם המפתח 1mypassword, השורה השניה עם המפתח 2mypassword וכו'.
תגובות לכתבה:
תגיד לי, באלך לאבטח לי את האתר חח?
תהיה בריא, אתה חכם מידי =]
איך אני משתמש בזה ב-YII?
בצורה רגילה. זה בסה"כ שאילתה. באותה צורה שאתה מפעיל ב YII שאילתות - תפעיל את השאילתה הזאת. לדגמה:
Yii::app()->db->createCommand("UPDATE `destest` SET
`encrypted` = DES_ENCRYPT(:string, CONCAT(`id`, :pass) )")->execute(array('string' => 'hello', 'pass' => 'password'));
איך אני משלב את זה עם מה שלמדנו במדריך :http://phpguide.co.il/מדריך לYii הפריימוורק הכי מתקדם של PHP חלק ד.htm?
במדריך 4 של YII למדנו להכניס למסד נתונים כך:
$account = new Account();
$account->username = $username;
$account->password = md5($password);
$account->email = $email;
$account->save();
איך אני מוסיף לזה את Yii::app()->db->createCommand("UPDATE `destest` SET
`encrypted` = DES_ENCRYPT(:string, CONCAT(`id`, :pass) )")->execute(array('string' => 'hello', 'pass' => 'password'));
?
או שזה או זה או זה?
$encrytionkey = 'somethingblabalbalbal';
$email = $account->mail; // = '[email protected]';
$account->mail = new CDbExpression(DES_ENCRYPT(:string, CONCAT(`id`, :encryptionkey) ), array('string'=>$email, 'encryptionkey' => $encriptionkey));
לא הבנתי איך להוסיף את זה.
זה הקוד שלי:
$emails = new Emails();
$emails->email = $email;
$emails->save();
echo "האימייל נרשם בהצלחה!";
את השורה $encrytionkey = 'somethingblabalbalbal'; הבנתי, ומהשורה הבאה לא הבנתי מה לעשות.
אפשר הסבר ? ואיפה להוסיף את מה שנתת בקוד שלי?
נתמך בגרסא MySQL 5.5 ומעלה נכון ?
ואפילו הרבה לפני
מכיוון שהיה לי בעיה להשתמש בזה, הלכתי לפי המדריך והעתקתי את כל הקודים שנתת.
פתחתי את הטבלה, וכתבתי את השאילתה שמכניסה למסד, את הINSERT.
כשאני מריץ את זה, זה פשוט מראה לי את השגיאה:
"Column 'encrypted' cannot be null"
יכול להיות שזה לא תומך ?, אני מזכיר, כל הקודים אותו דבר כמו במדריך...
ד"א, הגירסא שמותקנת על השרת היא MySQL 5.0.67
את איזה קוד ספציפי מהמדריך אתה מפעיל כשאתה מקבל שגיאה?
INSERT INTO `destest` (`id`, `encrypted`) VALUES(1, DES_ENCRYPT('phpguide.co.il', 'password') )